// webpack是node写的，需要使用node语法

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')            // html静态模版
const MinCssExtractPlugin = require('mini-css-extract-plugin')      // 抽离css为单独文件
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')  // 样式压缩
const Uglifyjs = require('uglifyjs-webpack-plugin')                 // js压缩
const { CleanWebpackPlugin } = require('clean-webpack-plugin')      // 清除文件
const CopyWebpackPlugin = require('copy-webpack-plugin')            // 拷贝文件
const HtmlWebpackExternalsPlugin = require('html-webpack-externals-plugin')
const TerserPlugin = require('terser-webpack-plugin');
const webpack = require('webpack')


// const dotenvPath = '.env.dev'  // .env.dev||.env.pord
// require('dotenv-expand')(
//   require('dotenv').config({
//     path: dotenvPath
//   })
// )

// console.log('=======', process.env.name);



module.exports = {
  /** 模式，默认有development 和 production*/
  mode: 'development',
  /** 
   * 优化项
   * 在production下如果不配置optimization则自动压缩js
   */
  optimization: {
    // minimize: true,
    minimizer: [
      /** 
       * 在生产环境开启 CSS 优化。 如果还想在开发环境下启用 CSS 优化，请将 optimization.minimize 设置为 true
       * 目前和postcss冲突，暂未解决，怀疑是版本问题
       * 将postcss-loader版本降到3.x后解决该问题
       */
      // 压缩js
      new CssMinimizerPlugin(),
      // new Uglifyjs({
      //   cache: true,   // 是否缓存
      //   parallel: true,  // 是否并发打包
      //   sourceMap: true  // 是否开启sourceMap
      // })
      // 压缩js  webpack5中该插件内置了，替代以前的Uglifyjs插件
      // Uglifyjs不能压缩es6语法，TerserPlugin则可以。
      new TerserPlugin()
    ],
  },
  // 只要改代码就会打包
  // watch: true,
  /**
   * 源码映射，babel会将高级语法解析成es5语法，并且将代码压缩。导致调试时找不到报错位置，所以需要sourceMap
   * 1)source-map  2)eval-source-map  3)cheap-module-source-map  4)cheap-module-eval-source-map  
   */
  devtool: 'eval-source-map',

  /** 
   * 引入第三方包时从那个路径开始
   * webpack使用的commonjs标准，默认从当前根路径下的node_modules中查找，找不到去上层路径中的node_modules中查找
   * 我们可以配置允许去其他路径中查找
   */
  resolve: {
    modules: [
      path.resolve(__dirname, 'myLib'),
      path.resolve(__dirname, 'node_modules')
    ],
    // 引入模块时添加上扩展名
    extensions: ['.js', '.css', '.json', '.vue'],
    // 设置别名
    alias: {
      '@': path.resolve(__dirname, 'src')
    }
  },
  /** 开发服务器的配置 */
  devServer: {
    // host: 'http://127.0.0.1:3000',
    port: 3000,  // 端口
    progress: true,  // 打包时显示打包进度
    contentBase: path.join(__dirname, 'dist'),  // 以那个文件夹为服务器需要的静态文件
    proxy: {
      '/api': {
        target: 'http://localhost:3000',  // 代理到的地址
        pathRewrite: {  // 重写，把/api前缀去除
          '/api': ''
        }
      }
    }
  },
  /** 入口 */
  entry: './src/index.js',
  /** 出口 */
  output: {
    assetModuleFilename: 'images/[hash][ext][query]',
    /** 打包后的文件名, */
    // filename:'bundle.[hash:8].js', // 控制hash值的长度
    // filename:'bundle.[hash].js',  // 每次生成不同的hash值，防止缓存
    filename: 'bundle.js',
    /** 打包后的路径,路径必须是一个绝对路径 */
    path: path.resolve(__dirname, 'dist'),
    /** 
     * 所有的公共资源都会加上这个域名路径，可以在图片（url-loader）中单独设置publicPath
     * 如果样式/图片后期放入到cdn上做优化时，就可以使用这个功能加上cdn的域名地址
     */
    // publicPath: 'ldx/'
  },
  plugins: [
    // new webpack.SourceMapDevToolPlugin({
    //   append: '\n//# sourceMappingURL=http://127.0.0.1:8081/[url]',
    //   filename: '[file].map',
    // }),
    // new FileManagerPlugin({
    //   events: {
    //     onEnd: {
    //       copy: [{
    //         source: './dist/*.map',
    //         destination: 'C:/aprepare/zhufengwebpack2021/1.basic/sourcemap',
    //       }],
    //       delete: ['./dist/*.map'],
    //     },
    //   },
    // }),
    new HtmlWebpackPlugin({
      /** html模版路径 */
      template: path.resolve(__dirname, 'public/index.html'),
      /** 打包后的html文件名称 */
      filename: 'index.html',
      /** 压缩，最小化代码量 */
      // minify: {
      //   /** 删除单引号 */
      //   removeAttributeQuotes: true,
      //   /** 折叠成一行 */
      //   collapseWhitespace: true
      // },
      /** html文件中标签引入的js/css文件后加上hash值 bundle.js?hash值 */
      hash: true
    }),
    new MinCssExtractPlugin({
      /** 抽离后的css文件名 */
      filename: 'css/main.css',
    }),
    /** 在每个模块中都注入$对象 */
    new webpack.ProvidePlugin({
      $: 'jquery'
    }),
    new webpack.ProgressPlugin(),
    /** 清除文件,以文件的输出地址为清除地址 */
    new CleanWebpackPlugin(),
    /** 拷贝文件，从doc文件名称拷贝到dist/doc文件名称 */
    new CopyWebpackPlugin({
      patterns: [
        { from: "doc", to: "doc" },
      ]
    }),
    /** 版权声明插件,在js/css文件中最前面插入这句话 */
    new webpack.BannerPlugin('2021 ldx'),
    /** 设置环境变量,在模块中直接使用‘ENV’变量 */
    new webpack.DefinePlugin({
      ENV: JSON.stringify('dev')
    }),
    /** 类似externals，但不需要手动配置cdn */
    new HtmlWebpackExternalsPlugin({
      externals: [
        {
          module: 'lodash', // 模块名
          entry: "https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.20/lodash.js",
          global: '_', // 全局变量名
        },
      ]
    }),
  ],
  /** 外部扩展 */
  externals: {
    jquery: '$',
  },
  module: {  // 模块
    /** 规则 */
    rules: [
      {
        test: /\.html$/,
        loader: 'html-withimg-loader',
      },
      // {
      //   test: /\.(png|jpeg|jpg)$/,
      //   loader: 'url-loader',
      //   options: {
      //     // 不使用esModule模块化
      //     esModule: false,
      //     limlt: 200 * 1024,
      //     // 打包文件路径
      //     outputPath: 'img/',
      //     /** 
      //      * 如果图片后期放入到cdn上做优化时，就可以使用这个功能加上cdn的域名地址
      //      */
      //     publicPath: 'ldx/'
      //   }
      // },
      {
        test: /\.(png|jpg)$/,
        type: 'asset/resource'
      },
      {
        /** 当代码中引用了jquery，就会匹配这个rules规则 */
        test: require.resolve('jquery'),
        loader: 'expose-loader',
        options: {
          exposes: ["$", "jQuery"],
        },
      },
      // {
      //   test: /\.js$/,
      //   exclude: /node_module/,
      //   use: {
      //     loader: 'eslint-loader',
      //     options: {
      //       /** 
      //        * loader默认是从右向左，从下到上执行的
      //        * 但是eslint需要在babel语法转化前先执行，可以通过配置enforce进行设置
      //        * pre  normal post  三种执行顺序，默认是normal
      //        */
      //       enforce: 'pre'
      //     }
      //   }
      // },
      {
        test: /\.js$/,
        /** 排除node_module下的文件解析 */
        exclude: /node_module/,
        /** 只解析src文件夹下的js代码 */
        include: path.resolve(__dirname, 'src'),
        use: {
          loader: 'babel-loader',
          options: {  // 用babel-loader，需要把es6转成es5
            presets: [  // 预设,大插件的集合
              '@babel/preset-env'
            ],
            plugins: [  // 在预设之外需要的一个个小插件
              '@babel/plugin-proposal-class-properties',
              '@babel/plugin-transform-runtime'
            ]
          }
        }
      },
      /** 
       * style-loader 将css插入到html的head标签中
       * css-loader 解析 @import 这种写法
       * loader的特点，希望用途单一，所以需要多个loader组合使用
       * loader可以是一个字符串，数组或者对象，对象的好处是可以传入options参数
      */
      // {
      //   test: /\.css$/, use: [
      //     // {
      //     //   loader: 'style-loader',
      //     //   options: {
      //     //     insert: 'top' // 将style样式插入到html的顶部
      //     //   }
      //     // }
      //     MinCssExtractPlugin.loader, 'css-loader', 'postcss-loader']
      // },
      {
        test: /\.(css|less)$/, use: [MinCssExtractPlugin.loader, {
          loader:'css-loader',
          options: {
            /**
             * @import './xxx.less' 引入的样式也需要less-loader和postcss-loader解析
             * @import是css语法，不走webpack的require流程，所以需要单独配置该属性，在内部重新走loader解析
             * less-loader可以解析@import语法，所以不设置importLoaders也可以，但是如果不设置less-loader的话必须设置importLoaders
             */
            importLoaders: 2 
          }
        }, 'postcss-loader', 'less-loader']
      }
    ],
  }
}